//! Epic 3 - 配置管理系统集成测试
//!
//! Story 3.1: 定义配置结构体

#![allow(clippy::expect_fun_call)]

use std::collections::HashMap;

use log4r::config::{
    AppendersConfig, AsyncConfig, ConsoleConfig, ConsoleTarget, FileConfig, FormatConfig,
    Log4rConfig, TimeZone,
};
use log4r::Level;

// ============================================================================
// AC-3.1.1: Log4rConfig 主配置结构体
// ============================================================================

/// GIVEN: 调用 Log4rConfig::default()
/// WHEN: 检查所有字段
/// THEN: 返回正确的默认值
#[test]
fn test_log4r_config_default_values() {
    let config = Log4rConfig::default();

    assert_eq!(config.level, Level::Info, "默认级别应该是 Info");
    assert_eq!(config.app_name, "log4r", "默认应用名应该是 log4r");
    assert!(config.modules.is_empty(), "默认模块覆盖应该为空");
    assert!(
        config.appenders.console.is_none(),
        "默认 console 配置应该为 None"
    );
    assert!(config.appenders.file.is_none(), "默认 file 配置应该为 None");
}

/// GIVEN: Log4rConfig 结构体
/// WHEN: 检查字段类型
/// THEN: 包含所有必需字段
#[test]
fn test_log4r_config_has_all_fields() {
    let config = Log4rConfig {
        level: Level::Debug,
        app_name: "test-app".to_string(),
        modules: {
            let mut m = HashMap::new();
            m.insert("my_app::db".to_string(), Level::Trace);
            m
        },
        appenders: AppendersConfig::default(),
        format: FormatConfig::default(),
        async_config: AsyncConfig::default(),
    };

    assert_eq!(config.level, Level::Debug);
    assert_eq!(config.app_name, "test-app");
    assert_eq!(config.modules.get("my_app::db"), Some(&Level::Trace));
}

// ============================================================================
// AC-3.1.2: AppendersConfig 结构体
// ============================================================================

/// GIVEN: 调用 AppendersConfig::default()
/// WHEN: 检查字段
/// THEN: console 和 file 都为 None
#[test]
fn test_appenders_config_default() {
    let config = AppendersConfig::default();

    assert!(config.console.is_none());
    assert!(config.file.is_none());
}

/// GIVEN: AppendersConfig 结构体
/// WHEN: 设置 console 和 file
/// THEN: 可以正确存储配置
#[test]
fn test_appenders_config_with_values() {
    let config = AppendersConfig {
        console: Some(ConsoleConfig::default()),
        file: Some(FileConfig {
            enabled: true,
            path: "logs/app.log".to_string(),
            level: None,
            max_size: None,
            rotation: None,
            max_files: Some(7),
        }),
    };

    assert!(config.console.is_some());
    assert!(config.file.is_some());
}

// ============================================================================
// AC-3.1.3: ConsoleConfig 结构体
// ============================================================================

/// GIVEN: 调用 ConsoleConfig::default()
/// WHEN: 检查字段
/// THEN: enabled=true, target=Stdout, level=None
#[test]
fn test_console_config_default() {
    let config = ConsoleConfig::default();

    assert!(config.enabled, "默认应该启用");
    assert_eq!(
        config.target,
        ConsoleTarget::Stdout,
        "默认目标应该是 Stdout"
    );
    assert!(config.level.is_none(), "默认级别应该为 None");
}

/// GIVEN: ConsoleConfig 结构体
/// WHEN: 设置所有字段
/// THEN: 可以正确存储配置
#[test]
fn test_console_config_with_values() {
    let config = ConsoleConfig {
        enabled: false,
        target: ConsoleTarget::Stderr,
        level: Some(Level::Warn),
        colored: false,
    };

    assert!(!config.enabled);
    assert_eq!(config.target, ConsoleTarget::Stderr);
    assert_eq!(config.level, Some(Level::Warn));
    assert!(!config.colored);
}

// ============================================================================
// AC-3.1.4: FileConfig 结构体
// ============================================================================

/// GIVEN: FileConfig 结构体
/// WHEN: 创建实例
/// THEN: 包含 enabled, path, level 字段
#[test]
fn test_file_config_fields() {
    let config = FileConfig {
        enabled: true,
        path: "logs/app.log".to_string(),
        level: Some(Level::Debug),
        max_size: None,
        rotation: None,
        max_files: Some(7),
    };

    assert!(config.enabled);
    assert_eq!(config.path, "logs/app.log");
    assert_eq!(config.level, Some(Level::Debug));
}

/// GIVEN: FileConfig 结构体
/// WHEN: level 为 None
/// THEN: 表示使用全局级别
#[test]
fn test_file_config_level_optional() {
    let config = FileConfig {
        enabled: true,
        path: "logs/app.log".to_string(),
        level: None,
        max_size: None,
        rotation: None,
        max_files: Some(7),
    };

    assert!(config.level.is_none());
}

// ============================================================================
// AC-3.1.5: FormatConfig 结构体
// ============================================================================

/// GIVEN: 调用 FormatConfig::default()
/// WHEN: 检查字段
/// THEN: 返回正确的默认格式
#[test]
fn test_format_config_default() {
    let config = FormatConfig::default();

    assert_eq!(config.pattern, "{time} [{level}] {target}: {message}");
    assert_eq!(
        config.time_format,
        "[year]-[month]-[day] [hour]:[minute]:[second]"
    );
    assert_eq!(config.time_zone, TimeZone::Local);
}

/// GIVEN: FormatConfig 结构体
/// WHEN: 设置自定义格式
/// THEN: 可以正确存储配置
#[test]
fn test_format_config_custom() {
    let config = FormatConfig {
        pattern: "{message}".to_string(),
        time_format: "[hour]:[minute]".to_string(),
        time_zone: TimeZone::Utc,
    };

    assert_eq!(config.pattern, "{message}");
    assert_eq!(config.time_format, "[hour]:[minute]");
    assert_eq!(config.time_zone, TimeZone::Utc);
}

// ============================================================================
// AC-3.1.6: AsyncConfig 结构体
// ============================================================================

/// GIVEN: 调用 AsyncConfig::default()
/// WHEN: 检查字段
/// THEN: enabled=true, queue_size=10000
#[test]
fn test_async_config_default() {
    let config = AsyncConfig::default();

    assert!(config.enabled, "默认应该启用异步");
    assert_eq!(config.queue_size, 10000, "默认队列大小应该是 10000");
}

/// GIVEN: AsyncConfig 结构体
/// WHEN: 设置自定义值
/// THEN: 可以正确存储配置
#[test]
fn test_async_config_custom() {
    use log4r::config::BackpressureStrategy;

    let config = AsyncConfig {
        enabled: false,
        queue_size: 50000,
        backpressure: BackpressureStrategy::Block,
        ..Default::default()
    };

    assert!(!config.enabled);
    assert_eq!(config.queue_size, 50000);
    assert_eq!(config.backpressure, BackpressureStrategy::Block);
    // Story 14.4: 验证批量配置默认值
    assert_eq!(config.batch_size, 100);
    assert_eq!(config.batch_timeout_ms, 100);
}

// ============================================================================
// AC-3.1.7: serde::Deserialize 实现
// ============================================================================

/// GIVEN: 有效的 TOML 配置字符串
/// WHEN: 使用 toml::from_str 反序列化
/// THEN: 返回正确的 Log4rConfig
#[test]
fn test_deserialize_log4r_config() {
    let toml_str = r#"
        level = "debug"
        app_name = "test-app"
    "#;

    let config: Log4rConfig = toml::from_str(toml_str).expect("有效的 TOML 配置应该成功解析");

    assert_eq!(config.level, Level::Debug);
    assert_eq!(config.app_name, "test-app");
}

/// GIVEN: 包含 modules 的 TOML 配置
/// WHEN: 使用 toml::from_str 反序列化
/// THEN: modules HashMap 正确解析
#[test]
fn test_deserialize_modules() {
    let toml_str = r#"
        level = "info"

        [modules]
        "my_app::db" = "debug"
        "my_app::http" = "warn"
    "#;

    let config: Log4rConfig = toml::from_str(toml_str).expect("有效的 TOML 配置应该成功解析");

    assert_eq!(config.modules.get("my_app::db"), Some(&Level::Debug));
    assert_eq!(config.modules.get("my_app::http"), Some(&Level::Warn));
}

/// GIVEN: 包含 appenders 的 TOML 配置
/// WHEN: 使用 toml::from_str 反序列化
/// THEN: appenders 正确解析
#[test]
fn test_deserialize_appenders() {
    let toml_str = r#"
        level = "info"

        [appenders.console]
        enabled = true
        target = "stderr"
        level = "warn"

        [appenders.file]
        enabled = true
        path = "logs/app.log"
        level = "debug"
    "#;

    let config: Log4rConfig = toml::from_str(toml_str).expect("有效的 TOML 配置应该成功解析");

    let console = config.appenders.console.expect("console 配置应该存在");
    assert!(console.enabled);
    assert_eq!(console.target, ConsoleTarget::Stderr);
    assert_eq!(console.level, Some(Level::Warn));

    let file = config.appenders.file.expect("file 配置应该存在");
    assert!(file.enabled);
    assert_eq!(file.path, "logs/app.log");
    assert_eq!(file.level, Some(Level::Debug));
}

/// GIVEN: 包含 format 的 TOML 配置
/// WHEN: 使用 toml::from_str 反序列化
/// THEN: format 正确解析
#[test]
fn test_deserialize_format() {
    let toml_str = r#"
        level = "info"

        [format]
        pattern = "{message}"
        time_format = "[hour]:[minute]"
        time_zone = "utc"
    "#;

    let config: Log4rConfig = toml::from_str(toml_str).expect("有效的 TOML 配置应该成功解析");

    assert_eq!(config.format.pattern, "{message}");
    assert_eq!(config.format.time_format, "[hour]:[minute]");
    assert_eq!(config.format.time_zone, TimeZone::Utc);
}

/// GIVEN: 包含 async 的 TOML 配置
/// WHEN: 使用 toml::from_str 反序列化
/// THEN: async_config 正确解析
#[test]
fn test_deserialize_async() {
    let toml_str = r#"
        level = "info"

        [async]
        enabled = false
        queue_size = 50000
    "#;

    let config: Log4rConfig = toml::from_str(toml_str).expect("有效的 TOML 配置应该成功解析");

    assert!(!config.async_config.enabled);
    assert_eq!(config.async_config.queue_size, 50000);
}

/// GIVEN: 级别名称使用不同大小写
/// WHEN: 使用 toml::from_str 反序列化
/// THEN: 大小写不敏感地解析
#[test]
fn test_deserialize_level_case_insensitive() {
    let test_cases = vec![
        ("INFO", Level::Info),
        ("info", Level::Info),
        ("Info", Level::Info),
        ("DEBUG", Level::Debug),
        ("debug", Level::Debug),
        ("TRACE", Level::Trace),
        ("WARN", Level::Warn),
        ("ERROR", Level::Error),
        ("FATAL", Level::Fatal),
    ];

    for (level_str, expected) in test_cases {
        let toml_str = format!("level = \"{}\"", level_str);
        let config: Log4rConfig =
            toml::from_str(&toml_str).expect(&format!("应该解析级别: {}", level_str));
        assert_eq!(config.level, expected, "级别 {} 解析失败", level_str);
    }
}

/// GIVEN: 最小配置（仅必需字段）
/// WHEN: 使用 toml::from_str 反序列化
/// THEN: 其他字段使用默认值
#[test]
fn test_deserialize_minimal_config() {
    let toml_str = "";

    let config: Log4rConfig = toml::from_str(toml_str).expect("空配置应该成功解析");

    assert_eq!(config.level, Level::Info);
    assert_eq!(config.app_name, "log4r");
    assert!(config.modules.is_empty());
    assert!(config.async_config.enabled);
    assert_eq!(config.async_config.queue_size, 10000);
}

// ============================================================================
// AC-3.1.8: 合理的默认值
// ============================================================================

/// GIVEN: 所有配置结构体
/// WHEN: 调用 default()
/// THEN: 返回合理的默认值
#[test]
fn test_all_defaults_are_reasonable() {
    // Log4rConfig 默认值
    let config = Log4rConfig::default();
    assert_eq!(
        config.level,
        Level::Info,
        "默认级别应该是 Info（生产环境常用）"
    );
    assert_eq!(config.app_name, "log4r", "默认应用名应该是 log4r");

    // AsyncConfig 默认值
    let async_config = AsyncConfig::default();
    assert!(async_config.enabled, "默认应该启用异步（性能更好）");
    assert_eq!(async_config.queue_size, 10000, "默认队列大小应该是 10000");

    // FormatConfig 默认值
    let format_config = FormatConfig::default();
    assert!(
        format_config.pattern.contains("{time}"),
        "默认格式应该包含时间"
    );
    assert!(
        format_config.pattern.contains("{level}"),
        "默认格式应该包含级别"
    );
    assert!(
        format_config.pattern.contains("{message}"),
        "默认格式应该包含消息"
    );
    assert_eq!(
        format_config.time_zone,
        TimeZone::Local,
        "默认时区应该是本地时区"
    );

    // ConsoleConfig 默认值
    let console_config = ConsoleConfig::default();
    assert!(console_config.enabled, "默认应该启用控制台输出");
    assert_eq!(
        console_config.target,
        ConsoleTarget::Stdout,
        "默认应该输出到 stdout"
    );
}

// ============================================================================
// AC-3.1.9: Send + Sync 实现
// ============================================================================

/// GIVEN: 所有配置结构体
/// WHEN: 编译时检查
/// THEN: 都实现 Send + Sync
#[test]
fn test_all_configs_are_send_sync() {
    fn assert_send_sync<T: Send + Sync>() {}

    assert_send_sync::<Log4rConfig>();
    assert_send_sync::<AppendersConfig>();
    assert_send_sync::<ConsoleConfig>();
    assert_send_sync::<FileConfig>();
    assert_send_sync::<FormatConfig>();
    assert_send_sync::<AsyncConfig>();
    assert_send_sync::<ConsoleTarget>();
    assert_send_sync::<TimeZone>();
}

/// GIVEN: Log4rConfig 实例
/// WHEN: 在多线程环境中使用
/// THEN: 可以安全地跨线程传递
#[test]
fn test_config_can_be_shared_across_threads() {
    use std::sync::Arc;
    use std::thread;

    let config = Arc::new(Log4rConfig::default());
    let config_clone = Arc::clone(&config);

    let handle = thread::spawn(move || {
        assert_eq!(config_clone.level, Level::Info);
        assert_eq!(config_clone.app_name, "log4r");
    });

    handle.join().expect("线程应该成功完成");
}

// ============================================================================
// 枚举类型测试
// ============================================================================

/// GIVEN: ConsoleTarget 枚举
/// WHEN: 反序列化小写字符串
/// THEN: 正确解析
#[test]
fn test_console_target_deserialize() {
    #[derive(serde::Deserialize)]
    struct TestStruct {
        target: ConsoleTarget,
    }

    let toml_str = "target = \"stdout\"";
    let result: TestStruct = toml::from_str(toml_str).expect("应该成功解析");
    assert_eq!(result.target, ConsoleTarget::Stdout);

    let toml_str = "target = \"stderr\"";
    let result: TestStruct = toml::from_str(toml_str).expect("应该成功解析");
    assert_eq!(result.target, ConsoleTarget::Stderr);
}

/// GIVEN: TimeZone 枚举
/// WHEN: 反序列化小写字符串
/// THEN: 正确解析
#[test]
fn test_timezone_deserialize() {
    #[derive(serde::Deserialize)]
    struct TestStruct {
        time_zone: TimeZone,
    }

    let toml_str = "time_zone = \"local\"";
    let result: TestStruct = toml::from_str(toml_str).expect("应该成功解析");
    assert_eq!(result.time_zone, TimeZone::Local);

    let toml_str = "time_zone = \"utc\"";
    let result: TestStruct = toml::from_str(toml_str).expect("应该成功解析");
    assert_eq!(result.time_zone, TimeZone::Utc);
}

// ============================================================================
// Clone 和 Debug 测试
// ============================================================================

/// GIVEN: 所有配置结构体
/// WHEN: 调用 clone()
/// THEN: 返回相等的副本
#[test]
fn test_config_clone() {
    let config = Log4rConfig::default();
    let cloned = config.clone();

    assert_eq!(config, cloned);
}

/// GIVEN: 所有配置结构体
/// WHEN: 调用 Debug 格式化
/// THEN: 返回有意义的字符串
#[test]
fn test_config_debug() {
    let config = Log4rConfig::default();
    let debug_str = format!("{:?}", config);

    assert!(debug_str.contains("Log4rConfig"));
    assert!(debug_str.contains("level"));
    assert!(debug_str.contains("app_name"));
}

// ============================================================================
// Story 3.2: 实现 TOML 配置解析 - parse_config 集成测试
// ============================================================================

use log4r::config::parse_config;

// ============================================================================
// AC-3.2.1: 成功解析有效的 TOML 配置字符串
// ============================================================================

/// GIVEN: 完整的 TOML 配置字符串
/// WHEN: 调用 parse_config
/// THEN: 返回 Ok(Log4rConfig) 包含所有解析的字段
#[test]
fn test_parse_config_full_toml() {
    let toml = r#"
[log4r]
level = "debug"
app_name = "integration-test-app"

[log4r.modules]
"my_app::db" = "trace"
"my_app::http" = "warn"

[log4r.appenders.console]
enabled = true
target = "stderr"
level = "info"

[log4r.appenders.file]
enabled = true
path = "logs/integration.log"
level = "debug"

[log4r.format]
pattern = "{time} - {message}"
time_format = "[hour]:[minute]:[second]"
time_zone = "utc"

[log4r.async]
enabled = false
queue_size = 20000
"#;

    let config = parse_config(toml).expect("完整配置应成功解析");

    assert_eq!(config.level, Level::Debug);
    assert_eq!(config.app_name, "integration-test-app");
    assert_eq!(config.modules.len(), 2);
    assert_eq!(config.modules.get("my_app::db"), Some(&Level::Trace));
    assert_eq!(config.modules.get("my_app::http"), Some(&Level::Warn));

    let console = config.appenders.console.expect("console 应存在");
    assert!(console.enabled);
    assert_eq!(console.target, ConsoleTarget::Stderr);
    assert_eq!(console.level, Some(Level::Info));

    let file = config.appenders.file.expect("file 应存在");
    assert!(file.enabled);
    assert_eq!(file.path, "logs/integration.log");
    assert_eq!(file.level, Some(Level::Debug));

    assert_eq!(config.format.pattern, "{time} - {message}");
    assert_eq!(config.format.time_zone, TimeZone::Utc);

    assert!(!config.async_config.enabled);
    assert_eq!(config.async_config.queue_size, 20000);
}

// ============================================================================
// AC-3.2.2: 支持 [log4r] 顶级配置节解析
// ============================================================================

/// GIVEN: 带 [log4r] 前缀的配置
/// WHEN: 调用 parse_config
/// THEN: 正确解析
#[test]
fn test_parse_config_with_log4r_prefix() {
    let toml = r#"
[log4r]
level = "warn"
app_name = "prefixed"
"#;

    let config = parse_config(toml).expect("带前缀配置应成功解析");
    assert_eq!(config.level, Level::Warn);
    assert_eq!(config.app_name, "prefixed");
}

/// GIVEN: 无 [log4r] 前缀的配置
/// WHEN: 调用 parse_config
/// THEN: 直接解析为 Log4rConfig
#[test]
fn test_parse_config_without_log4r_prefix() {
    let toml = r#"
level = "error"
app_name = "direct"
"#;

    let config = parse_config(toml).expect("无前缀配置应成功解析");
    assert_eq!(config.level, Level::Error);
    assert_eq!(config.app_name, "direct");
}

// ============================================================================
// AC-3.2.3: 支持嵌套配置节解析
// ============================================================================

/// GIVEN: 包含所有嵌套配置节的 TOML
/// WHEN: 调用 parse_config
/// THEN: 所有嵌套配置正确解析
#[test]
fn test_parse_config_nested_sections() {
    let toml = r#"
[log4r]
level = "info"

[log4r.appenders.console]
enabled = true

[log4r.appenders.file]
enabled = false
path = "test.log"

[log4r.format]
pattern = "custom"

[log4r.async]
queue_size = 5000

[log4r.modules]
"test" = "debug"
"#;

    let config = parse_config(toml).expect("嵌套配置应成功解析");

    assert!(config.appenders.console.is_some());
    assert!(config.appenders.file.is_some());
    assert_eq!(config.format.pattern, "custom");
    assert_eq!(config.async_config.queue_size, 5000);
    assert_eq!(config.modules.get("test"), Some(&Level::Debug));
}

// ============================================================================
// AC-3.2.4: TOML 语法错误时返回 ConfigError，包含行号
// ============================================================================

/// GIVEN: TOML 语法错误
/// WHEN: 调用 parse_config
/// THEN: 返回 Err(ConfigError)
#[test]
fn test_parse_config_syntax_error() {
    let toml = r#"
[log4r
level = "info"
"#;

    let result = parse_config(toml);
    assert!(result.is_err(), "语法错误应返回 Err");

    let err = result.unwrap_err().to_string();
    assert!(err.contains("配置"), "错误信息应包含'配置'");
}

// ============================================================================
// AC-3.2.5: 字段类型错误时返回 ConfigError
// ============================================================================

/// GIVEN: 字段类型错误
/// WHEN: 调用 parse_config
/// THEN: 返回 Err(ConfigError)
#[test]
fn test_parse_config_type_error() {
    let toml = r#"
[log4r]
app_name = 123
"#;

    let result = parse_config(toml);
    assert!(result.is_err(), "类型错误应返回 Err");
}

// ============================================================================
// AC-3.2.6: 无效日志级别名称时返回 ConfigError
// ============================================================================

/// GIVEN: 无效的日志级别
/// WHEN: 调用 parse_config
/// THEN: 返回 Err(ConfigError)
#[test]
fn test_parse_config_invalid_level() {
    let toml = r#"
[log4r]
level = "invalid_level"
"#;

    let result = parse_config(toml);
    assert!(result.is_err(), "无效级别应返回 Err");
}

// ============================================================================
// AC-3.2.7: 支持大小写不敏感的级别名称解析
// ============================================================================

/// GIVEN: 不同大小写的级别名称
/// WHEN: 调用 parse_config
/// THEN: 都能正确解析为对应级别
#[test]
fn test_parse_config_level_case_insensitive() {
    let cases = vec![
        ("INFO", Level::Info),
        ("info", Level::Info),
        ("Info", Level::Info),
        ("DEBUG", Level::Debug),
        ("debug", Level::Debug),
        ("TRACE", Level::Trace),
        ("WARN", Level::Warn),
        ("ERROR", Level::Error),
        ("FATAL", Level::Fatal),
    ];

    for (level_str, expected) in cases {
        let toml = format!(
            r#"
[log4r]
level = "{}"
"#,
            level_str
        );

        let config = parse_config(&toml).expect(&format!("级别 {} 应成功解析", level_str));
        assert_eq!(config.level, expected, "级别 {} 解析结果不正确", level_str);
    }
}

// ============================================================================
// AC-3.2.8: 缺失的配置项使用默认值
// ============================================================================

/// GIVEN: 最小配置
/// WHEN: 调用 parse_config
/// THEN: 缺失字段使用默认值
#[test]
fn test_parse_config_defaults() {
    let toml = r#"
[log4r]
level = "debug"
"#;

    let config = parse_config(toml).expect("最小配置应成功解析");

    assert_eq!(config.level, Level::Debug);
    assert_eq!(config.app_name, "log4r"); // 默认值
    assert!(config.modules.is_empty()); // 默认值
    assert!(config.appenders.console.is_none()); // 默认值
    assert!(config.async_config.enabled); // 默认值
    assert_eq!(config.async_config.queue_size, 10000); // 默认值
}

// ============================================================================
// AC-3.2.9: 空配置字符串或仅包含注释的配置使用默认值
// ============================================================================

/// GIVEN: 空字符串
/// WHEN: 调用 parse_config
/// THEN: 返回默认配置
#[test]
fn test_parse_config_empty() {
    let config = parse_config("").expect("空配置应返回默认值");

    assert_eq!(config.level, Level::Info);
    assert_eq!(config.app_name, "log4r");
}

/// GIVEN: 仅包含注释的配置
/// WHEN: 调用 parse_config
/// THEN: 返回默认配置
#[test]
fn test_parse_config_comments_only() {
    let toml = r#"
# 这是一个注释
# 另一行注释

# 更多注释
"#;

    let config = parse_config(toml).expect("仅注释应返回默认值");

    assert_eq!(config.level, Level::Info);
    assert_eq!(config.app_name, "log4r");
}

// ============================================================================
// Story 3.3: 实现默认配置文件查找 - 集成测试
// ============================================================================

use log4r::config::{find_config, load_config, load_config_from_default};
use serial_test::serial;
use std::env;
use std::fs;
use std::path::PathBuf;
use tempfile::tempdir;

// ============================================================================
// AC-3.3.1: 按顺序查找配置文件
// ============================================================================

/// GIVEN: 当前目录存在 log4r.toml
/// WHEN: 调用 find_config
/// THEN: 返回 Some("log4r.toml")
#[test]
#[serial]
fn test_find_config_current_dir() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    fs::write("log4r.toml", "[log4r]\nlevel = \"debug\"").expect("写入文件失败");

    let result = find_config();
    assert_eq!(result, Some(PathBuf::from("log4r.toml")));

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

/// GIVEN: 仅 config 子目录存在 log4r.toml
/// WHEN: 调用 find_config
/// THEN: 返回 Some("config/log4r.toml")
#[test]
#[serial]
fn test_find_config_config_subdir() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    fs::create_dir("config").expect("创建目录失败");
    fs::write("config/log4r.toml", "[log4r]\nlevel = \"info\"").expect("写入文件失败");

    let result = find_config();
    assert_eq!(result, Some(PathBuf::from("config/log4r.toml")));

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

/// GIVEN: 当前目录和 config 子目录都存在 log4r.toml
/// WHEN: 调用 find_config
/// THEN: 返回当前目录的配置文件（优先级更高）
#[test]
#[serial]
fn test_find_config_priority_current_over_config() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    fs::write("log4r.toml", "[log4r]\nlevel = \"debug\"").expect("写入文件失败");
    fs::create_dir("config").expect("创建目录失败");
    fs::write("config/log4r.toml", "[log4r]\nlevel = \"info\"").expect("写入文件失败");

    let result = find_config();
    assert_eq!(result, Some(PathBuf::from("log4r.toml")));

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

// ============================================================================
// AC-3.3.4: 所有路径都不存在时返回 None
// ============================================================================

/// GIVEN: 没有任何配置文件
/// WHEN: 调用 find_config
/// THEN: 返回 None
#[test]
#[serial]
fn test_find_config_no_config_returns_none() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    let result = find_config();
    assert!(result.is_none(), "无配置文件时应返回 None");

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

// ============================================================================
// AC-3.3.5: 找到第一个存在的配置文件后立即返回
// ============================================================================

/// GIVEN: 多个位置都有配置文件
/// WHEN: 调用 find_config
/// THEN: 返回第一个找到的（按优先级顺序）
#[test]
#[serial]
fn test_find_config_returns_first_found() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    // 创建多个配置文件
    fs::write("log4r.toml", "[log4r]\nlevel = \"trace\"").expect("写入文件失败");
    fs::create_dir("config").expect("创建目录失败");
    fs::write("config/log4r.toml", "[log4r]\nlevel = \"debug\"").expect("写入文件失败");

    // 应返回第一个（当前目录）
    let result = find_config();
    assert_eq!(result, Some(PathBuf::from("log4r.toml")));

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

// ============================================================================
// AC-3.3.6: find_config() 返回 Option<PathBuf>
// ============================================================================

/// GIVEN: find_config 函数
/// WHEN: 检查返回类型
/// THEN: 返回 Option<PathBuf>
#[test]
fn test_find_config_return_type_is_option_pathbuf() {
    let result: Option<PathBuf> = find_config();
    // 编译通过即验证返回类型正确
    let _ = result;
}

// ============================================================================
// load_config 集成测试
// ============================================================================

/// GIVEN: 有效的配置文件路径
/// WHEN: 调用 load_config
/// THEN: 返回 Ok(Log4rConfig)
#[test]
fn test_load_config_valid_file() {
    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("test.toml");
    fs::write(
        &config_path,
        r#"
[log4r]
level = "warn"
app_name = "test-app"
"#,
    )
    .expect("写入文件失败");

    let config = load_config(&config_path).expect("加载配置应成功");
    assert_eq!(config.level, Level::Warn);
    assert_eq!(config.app_name, "test-app");
}

/// GIVEN: 不存在的文件路径
/// WHEN: 调用 load_config
/// THEN: 返回 Err(IoError)
#[test]
fn test_load_config_file_not_found() {
    let result = load_config("nonexistent_config_file.toml");
    assert!(result.is_err(), "不存在的文件应返回错误");
}

/// GIVEN: 无效的 TOML 文件
/// WHEN: 调用 load_config
/// THEN: 返回 Err(ConfigError)
#[test]
fn test_load_config_invalid_toml() {
    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("invalid.toml");
    fs::write(&config_path, "[log4r\nlevel = ").expect("写入文件失败");

    let result = load_config(&config_path);
    assert!(result.is_err(), "无效 TOML 应返回错误");
}

// ============================================================================
// load_config_from_default 集成测试
// ============================================================================

/// GIVEN: 没有配置文件
/// WHEN: 调用 load_config_from_default
/// THEN: 返回默认配置
#[test]
#[serial]
fn test_load_config_from_default_returns_default() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    let config = load_config_from_default().expect("应返回默认配置");
    assert_eq!(config.level, Level::Info);
    assert_eq!(config.app_name, "log4r");

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

/// GIVEN: 存在配置文件
/// WHEN: 调用 load_config_from_default
/// THEN: 加载并返回配置
#[test]
#[serial]
fn test_load_config_from_default_loads_file() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    fs::write(
        "log4r.toml",
        r#"
[log4r]
level = "error"
app_name = "loaded-app"
"#,
    )
    .expect("写入文件失败");

    let config = load_config_from_default().expect("应加载配置文件");
    assert_eq!(config.level, Level::Error);
    assert_eq!(config.app_name, "loaded-app");

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

/// GIVEN: 配置文件存在但内容无效
/// WHEN: 调用 load_config_from_default
/// THEN: 返回 Err(ConfigError)
#[test]
#[serial]
fn test_load_config_from_default_invalid_file() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    fs::write("log4r.toml", "[log4r\nlevel = ").expect("写入文件失败");

    let result = load_config_from_default();
    assert!(result.is_err(), "无效配置文件应返回错误");

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

// ============================================================================
// AC-3.3.2, AC-3.3.3: 跨平台用户配置目录
// ============================================================================

/// GIVEN: dirs::config_dir() 返回值
/// WHEN: 构建用户配置路径
/// THEN: 路径格式正确
#[test]
fn test_user_config_dir_path_format() {
    if let Some(config_dir) = dirs::config_dir() {
        let user_config = config_dir.join("log4r").join("log4r.toml");
        let path_str = user_config.to_string_lossy();

        // 验证路径包含 log4r 目录
        assert!(path_str.contains("log4r"), "路径应包含 log4r 目录");

        // 验证路径以 log4r.toml 结尾
        assert!(path_str.ends_with("log4r.toml"), "路径应以 log4r.toml 结尾");
    }
}

// ============================================================================
// Story 3.4: 实现代码指定配置路径 - 集成测试
// ============================================================================

// ============================================================================
// AC-3.4.1: load_config(path) 从指定路径加载配置
// ============================================================================

/// GIVEN: 有效的配置文件路径
/// WHEN: 调用 load_config(path)
/// THEN: 返回 Ok(Log4rConfig) 包含正确的配置值
#[test]
fn test_load_config_from_specified_path() {
    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("custom_config.toml");
    fs::write(
        &config_path,
        r#"
[log4r]
level = "debug"
app_name = "specified-path-app"
"#,
    )
    .expect("写入配置文件失败");

    let config = load_config(&config_path).expect("从指定路径加载配置应成功");
    assert_eq!(config.level, Level::Debug, "级别应为 debug");
    assert_eq!(config.app_name, "specified-path-app", "应用名应正确");
}

// ============================================================================
// AC-3.4.2: 支持相对路径和绝对路径
// ============================================================================

/// GIVEN: 相对路径配置文件
/// WHEN: 调用 load_config 使用相对路径
/// THEN: 成功加载配置
#[test]
#[serial]
fn test_load_config_with_relative_path() {
    let temp = tempdir().expect("创建临时目录失败");
    let original_dir = env::current_dir().expect("获取当前目录失败");
    env::set_current_dir(&temp).expect("切换目录失败");

    fs::write("relative_config.toml", "[log4r]\nlevel = \"trace\"").expect("写入文件失败");

    let config = load_config("relative_config.toml").expect("相对路径加载应成功");
    assert_eq!(config.level, Level::Trace, "级别应为 trace");

    env::set_current_dir(original_dir).expect("恢复目录失败");
}

/// GIVEN: 绝对路径配置文件
/// WHEN: 调用 load_config 使用绝对路径
/// THEN: 成功加载配置
#[test]
fn test_load_config_with_absolute_path() {
    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("absolute_config.toml");
    fs::write(&config_path, "[log4r]\nlevel = \"fatal\"").expect("写入文件失败");

    // 确保是绝对路径
    let absolute_path = config_path.canonicalize().expect("获取绝对路径失败");
    assert!(absolute_path.is_absolute(), "路径应为绝对路径");

    let config = load_config(&absolute_path).expect("绝对路径加载应成功");
    assert_eq!(config.level, Level::Fatal, "级别应为 fatal");
}

// ============================================================================
// AC-3.4.3: 文件不存在返回 Log4rError::IoError
// ============================================================================

/// GIVEN: 不存在的文件路径
/// WHEN: 调用 load_config
/// THEN: 返回 Err(Log4rError::IoError)
#[test]
fn test_load_config_nonexistent_file_returns_io_error() {
    use log4r::error::Log4rError;

    let result = load_config("/nonexistent/path/to/config.toml");
    assert!(result.is_err(), "不存在的文件应返回错误");

    match result.unwrap_err() {
        Log4rError::IoError(io_err) => {
            assert_eq!(
                io_err.kind(),
                std::io::ErrorKind::NotFound,
                "应为 NotFound 错误"
            );
        }
        other => panic!("应返回 IoError，实际返回: {:?}", other),
    }
}

// ============================================================================
// AC-3.4.4: 路径参数支持 &str, String, Path, PathBuf
// ============================================================================

/// GIVEN: &str 类型路径
/// WHEN: 调用 load_config
/// THEN: 成功加载配置
#[test]
fn test_load_config_accepts_str_path() {
    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("str_path.toml");
    fs::write(&config_path, "[log4r]\nlevel = \"info\"").expect("写入文件失败");

    let path_str: &str = config_path.to_str().expect("路径转字符串失败");
    let config = load_config(path_str).expect("&str 路径加载应成功");
    assert_eq!(config.level, Level::Info);
}

/// GIVEN: String 类型路径
/// WHEN: 调用 load_config
/// THEN: 成功加载配置
#[test]
fn test_load_config_accepts_string_path() {
    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("string_path.toml");
    fs::write(&config_path, "[log4r]\nlevel = \"warn\"").expect("写入文件失败");

    let path_string: String = config_path.to_string_lossy().to_string();
    let config = load_config(path_string).expect("String 路径加载应成功");
    assert_eq!(config.level, Level::Warn);
}

/// GIVEN: &Path 类型路径
/// WHEN: 调用 load_config
/// THEN: 成功加载配置
#[test]
fn test_load_config_accepts_path_ref() {
    use std::path::Path;

    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("path_ref.toml");
    fs::write(&config_path, "[log4r]\nlevel = \"error\"").expect("写入文件失败");

    let path_ref: &Path = config_path.as_path();
    let config = load_config(path_ref).expect("&Path 路径加载应成功");
    assert_eq!(config.level, Level::Error);
}

/// GIVEN: PathBuf 类型路径
/// WHEN: 调用 load_config
/// THEN: 成功加载配置
#[test]
fn test_load_config_accepts_pathbuf() {
    let temp = tempdir().expect("创建临时目录失败");
    let config_path: PathBuf = temp.path().join("pathbuf.toml");
    fs::write(&config_path, "[log4r]\nlevel = \"debug\"").expect("写入文件失败");

    let config = load_config(&config_path).expect("PathBuf 路径加载应成功");
    assert_eq!(config.level, Level::Debug);
}

/// GIVEN: PathBuf 类型路径（所有权转移）
/// WHEN: 调用 load_config 传入 PathBuf 值
/// THEN: 成功加载配置
#[test]
fn test_load_config_accepts_pathbuf_owned() {
    let temp = tempdir().expect("创建临时目录失败");
    let config_path: PathBuf = temp.path().join("pathbuf_owned.toml");
    fs::write(&config_path, "[log4r]\nlevel = \"trace\"").expect("写入文件失败");

    // 传入 PathBuf 值而非引用
    let config = load_config(config_path).expect("PathBuf 值加载应成功");
    assert_eq!(config.level, Level::Trace);
}

// ============================================================================
// AC-3.4.5: 解析失败返回 Log4rError::ConfigError
// ============================================================================

/// GIVEN: 包含无效 TOML 语法的配置文件
/// WHEN: 调用 load_config
/// THEN: 返回 Err(Log4rError::ConfigError)
#[test]
fn test_load_config_invalid_toml_returns_config_error() {
    use log4r::error::Log4rError;

    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("invalid_syntax.toml");
    fs::write(&config_path, "[log4r\nlevel = ").expect("写入文件失败");

    let result = load_config(&config_path);
    assert!(result.is_err(), "无效 TOML 应返回错误");

    match result.unwrap_err() {
        Log4rError::ConfigError(msg) => {
            assert!(!msg.is_empty(), "错误信息不应为空");
        }
        other => panic!("应返回 ConfigError，实际返回: {:?}", other),
    }
}

/// GIVEN: 包含无效日志级别的配置文件
/// WHEN: 调用 load_config
/// THEN: 返回 Err(Log4rError::ConfigError)
#[test]
fn test_load_config_invalid_level_returns_config_error() {
    use log4r::error::Log4rError;

    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("invalid_level.toml");
    fs::write(&config_path, "[log4r]\nlevel = \"invalid_level\"").expect("写入文件失败");

    let result = load_config(&config_path);
    assert!(result.is_err(), "无效级别应返回错误");

    match result.unwrap_err() {
        Log4rError::ConfigError(msg) => {
            assert!(!msg.is_empty(), "错误信息不应为空");
        }
        other => panic!("应返回 ConfigError，实际返回: {:?}", other),
    }
}

/// GIVEN: 包含类型错误的配置文件
/// WHEN: 调用 load_config
/// THEN: 返回 Err(Log4rError::ConfigError) 包含清晰的错误信息
#[test]
fn test_load_config_type_error_returns_config_error_with_message() {
    use log4r::error::Log4rError;

    let temp = tempdir().expect("创建临时目录失败");
    let config_path = temp.path().join("type_error.toml");
    fs::write(&config_path, "[log4r]\napp_name = 12345").expect("写入文件失败");

    let result = load_config(&config_path);
    assert!(result.is_err(), "类型错误应返回错误");

    match result.unwrap_err() {
        Log4rError::ConfigError(msg) => {
            // 验证错误信息包含有用的上下文
            assert!(
                msg.contains("配置") || msg.contains("config") || msg.contains("解析"),
                "错误信息应包含上下文: {}",
                msg
            );
        }
        other => panic!("应返回 ConfigError，实际返回: {:?}", other),
    }
}

// ============================================================================
// 补充测试 - Epic 3 ATDD 缺失场景
// ============================================================================

// ============================================================================
// 3.1-UNIT-005: 模块路径包含特殊字符
// ============================================================================

/// GIVEN: 模块路径包含下划线、数字等特殊字符
/// WHEN: 解析配置
/// THEN: 正确解析模块路径
#[test]
fn test_module_path_with_special_characters() {
    let toml = r#"
[log4r]
level = "info"

[log4r.modules]
"my_app::db::pool_v2" = "debug"
"my_app::http_client::v1_0" = "trace"
"my_app::cache_2024" = "warn"
"#;

    let config = parse_config(toml).expect("特殊字符模块路径应成功解析");

    assert_eq!(
        config.modules.get("my_app::db::pool_v2"),
        Some(&Level::Debug),
        "下划线和数字路径应正确解析"
    );
    assert_eq!(
        config.modules.get("my_app::http_client::v1_0"),
        Some(&Level::Trace),
        "版本号路径应正确解析"
    );
    assert_eq!(
        config.modules.get("my_app::cache_2024"),
        Some(&Level::Warn),
        "年份后缀路径应正确解析"
    );
}

/// GIVEN: 模块路径包含深层嵌套
/// WHEN: 解析配置
/// THEN: 正确解析深层嵌套路径
#[test]
fn test_module_path_deeply_nested() {
    let toml = r#"
[log4r]
level = "info"

[log4r.modules]
"my_app::services::user::repository::postgres" = "trace"
"my_app::api::v2::handlers::auth::oauth" = "debug"
"#;

    let config = parse_config(toml).expect("深层嵌套路径应成功解析");

    assert_eq!(
        config
            .modules
            .get("my_app::services::user::repository::postgres"),
        Some(&Level::Trace)
    );
    assert_eq!(
        config.modules.get("my_app::api::v2::handlers::auth::oauth"),
        Some(&Level::Debug)
    );
}

// ============================================================================
// 3.1-UNIT-006: 空模块配置
// ============================================================================

/// GIVEN: modules 配置节为空
/// WHEN: 解析配置
/// THEN: modules HashMap 为空，不报错
#[test]
fn test_empty_modules_config() {
    let toml = r#"
[log4r]
level = "info"

[log4r.modules]
"#;

    let config = parse_config(toml).expect("空 modules 配置应成功解析");

    assert!(config.modules.is_empty(), "空 modules 应返回空 HashMap");
}

/// GIVEN: 配置中没有 modules 节
/// WHEN: 解析配置
/// THEN: modules 使用默认值（空 HashMap）
#[test]
fn test_missing_modules_section() {
    let toml = r#"
[log4r]
level = "debug"
app_name = "no-modules-app"
"#;

    let config = parse_config(toml).expect("无 modules 节应成功解析");

    assert!(config.modules.is_empty(), "缺失 modules 节应返回空 HashMap");
}

// ============================================================================
// 3.2-UNIT-007: 未知字段处理（宽松模式）
// ============================================================================

/// GIVEN: 配置包含未知字段
/// WHEN: 解析配置
/// THEN: 忽略未知字段，不报错
#[test]
fn test_unknown_fields_ignored() {
    let toml = r#"
[log4r]
level = "info"
app_name = "test-app"
unknown_field = "should be ignored"
another_unknown = 12345

[log4r.unknown_section]
foo = "bar"
"#;

    let config = parse_config(toml).expect("未知字段应被忽略，不报错");

    assert_eq!(config.level, Level::Info);
    assert_eq!(config.app_name, "test-app");
}

/// GIVEN: appenders 配置包含未知字段
/// WHEN: 解析配置
/// THEN: 忽略未知字段，正确解析已知字段
#[test]
fn test_unknown_fields_in_appenders_ignored() {
    let toml = r#"
[log4r]
level = "info"

[log4r.appenders.console]
enabled = true
target = "stdout"
unknown_console_field = "ignored"

[log4r.appenders.file]
enabled = true
path = "logs/app.log"
unknown_file_field = 999
"#;

    let config = parse_config(toml).expect("appenders 中未知字段应被忽略");

    let console = config.appenders.console.expect("console 应存在");
    assert!(console.enabled);
    assert_eq!(console.target, ConsoleTarget::Stdout);

    let file = config.appenders.file.expect("file 应存在");
    assert!(file.enabled);
    assert_eq!(file.path, "logs/app.log");
}

// ============================================================================
// 3.3-INT-003: 查找用户配置目录（补充测试）
// ============================================================================

/// GIVEN: 用户配置目录存在配置文件
/// WHEN: 当前目录和 config 子目录都没有配置文件
/// THEN: 返回用户配置目录的路径
/// 注意：此测试在 CI 环境中可能跳过，因为需要写入用户配置目录
#[test]
fn test_user_config_dir_structure() {
    // 验证用户配置目录路径构建正确
    if let Some(config_dir) = dirs::config_dir() {
        let user_config_path = config_dir.join("log4r").join("log4r.toml");

        // 验证路径结构
        assert!(
            user_config_path.ends_with("log4r/log4r.toml")
                || user_config_path.ends_with("log4r\\log4r.toml"),
            "用户配置路径应以 log4r/log4r.toml 结尾: {:?}",
            user_config_path
        );
    }
}

// ============================================================================
// 边界情况补充测试
// ============================================================================

/// GIVEN: 配置值包含 Unicode 字符（中文）
/// WHEN: 解析配置
/// THEN: 正确处理 Unicode 字符
#[test]
fn test_unicode_values_in_config() {
    let toml = r#"
[log4r]
level = "info"
app_name = "我的应用程序"
"#;

    let config = parse_config(toml).expect("Unicode 值应成功解析");

    assert_eq!(config.app_name, "我的应用程序");
}

/// GIVEN: 配置路径包含空格
/// WHEN: 解析配置
/// THEN: 正确处理包含空格的路径
#[test]
fn test_path_with_spaces() {
    let toml = r#"
[log4r]
level = "info"

[log4r.appenders.file]
enabled = true
path = "logs/my app/application.log"
"#;

    let config = parse_config(toml).expect("包含空格的路径应成功解析");

    let file = config.appenders.file.expect("file 应存在");
    assert_eq!(file.path, "logs/my app/application.log");
}

/// GIVEN: 配置包含转义字符
/// WHEN: 解析配置
/// THEN: 正确处理转义字符
#[test]
fn test_escaped_characters_in_config() {
    let toml = r#"
[log4r]
level = "info"

[log4r.format]
pattern = "{time}\t[{level}]\t{message}"
"#;

    let config = parse_config(toml).expect("转义字符应成功解析");

    assert!(config.format.pattern.contains('\t'), "应包含制表符");
}
